﻿using In66.Net.Core.Core.Ids;
using In66.Net.Core.System.Extensions.Expressions;
using In66.Net.Repository.IRepositories.ISqlSugar;
using In66.Net.Share.Models.Dtos;

namespace Usr.Api.Services.Impl
{
    public class RoleAppService : AbstractAppService, IRoleAppService
    {
        private readonly ISugarBaseRepository<Role> _roleRepository;
        private readonly ISugarBaseRepository<User> _userRepository;
        private readonly ISugarBaseRepository<RoleRelation> _relationRepository;
        private readonly CacheService _cacheService;

        public RoleAppService(ISugarBaseRepository<Role> roleRepository,
            ISugarBaseRepository<User> userRepository,
            ISugarBaseRepository<RoleRelation> relationRepository,
            CacheService cacheService)
        {
            _roleRepository = roleRepository;
            _userRepository = userRepository;
            _relationRepository = relationRepository;
            _cacheService = cacheService;
        }

        public async Task<AppSrvResult<long>> CreateAsync(RoleCreationDto input)
        {
            input.TrimStringFields();
            var isExists = (await _cacheService.GetAllRolesFromCacheAsync()).Any(x => x.Name == input.Name);
            if (isExists)
            {
                return Problem(HttpStatusCode.BadRequest, "该角色名称已经存在");
            }

            var role = Mapper.Map<Role>(input);
            role.Id = IdGenerater.GetNextId();
            await _roleRepository.InsertAsync(role);

            return role.Id;
        }

        public async Task<AppSrvResult> UpdateAsync(long id, RoleUpdationDto input)
        {
            input.TrimStringFields();
            var isExists = (await _cacheService.GetAllRolesFromCacheAsync()).Any(x => x.Name == input.Name && x.Id != id);
            if (isExists)
            {
                return Problem(HttpStatusCode.BadRequest, "该角色名称已经存在");
            }

            var role = Mapper.Map<Role>(input);

            await _roleRepository.Update(s => s.Id == id, f => role);

            return AppSrvResult();
        }

        public async Task<AppSrvResult> DeleteAsync(long id)
        {
            if (id == 1600000000010)
            {
                return Problem(HttpStatusCode.Forbidden, "禁止删除初始角色");
            }

            if (await _userRepository.ExistsAsync(x => x.RoleIds == id.ToString()))
            {
                return Problem(HttpStatusCode.Forbidden, "有用户使用该角色，禁止删除");
            }

            await _roleRepository.DeleteByIdAsync(id);

            return AppSrvResult();
        }

        public async Task<AppSrvResult> SetPermissonsAsync(RoleSetPermissonsDto input)
        {
            if (input.RoleId == 1600000000010)
            {
                return Problem(HttpStatusCode.Forbidden, "禁止设置初始角色");
            }

            await _relationRepository.DeleteAsync(x => x.RoleId == input.RoleId);

            var relations = new List<RoleRelation>();
            foreach (var permissionId in input.Permissions)
            {
                relations.Add(
                    new RoleRelation
                    {
                        Id = IdGenerater.GetNextId(),
                        RoleId = input.RoleId,
                        MenuId = permissionId
                    }
                );
            }
            await _relationRepository.InsertAsync(relations);

            return AppSrvResult();
        }

        public async Task<RoleTreeDto> GetRoleTreeListByUserIdAsync(long userId)
        {
            RoleTreeDto result = null;
            IEnumerable<ZTreeNodeDto<long, dynamic>> treeNodes = null;

            var user = await _userRepository.QueryByClauseAsync(x => new { x.RoleIds }, x => x.Id == userId);
            if (user is null)
            {
                return null;
            }

            var roles = await _cacheService.GetAllRolesFromCacheAsync();
            var roleIds = user.RoleIds?.Split(',', StringSplitOptions.RemoveEmptyEntries).Select(x => long.Parse(x)) ?? new List<long>();
            if (roles.Any())
            {
                treeNodes = roles.Select(x => new ZTreeNodeDto<long, dynamic>
                {
                    Id = x.Id,
                    PID = x.Pid ?? 0,
                    Name = x.Name,
                    Open = !(x.Pid.HasValue && x.Pid.Value > 0),
                    Checked = roleIds.Contains(x.Id)
                });

                result = new RoleTreeDto
                {
                    TreeData = treeNodes.Select(x => new Node<long>
                    {
                        Id = x.Id,
                        PID = x.PID,
                        Name = x.Name,
                        Checked = x.Checked
                    }),
                    CheckedIds = treeNodes.Where(x => x.Checked).Select(x => x.Id)
                };
            }

            return result;
        }

        public async Task<PageModelVo<RoleDto>> GetPagedAsync(RolePagedSearchDto search)
        {
            search.TrimStringFields();
            var whereExpression = ExpressionCreator
                                                  .New<Role>()
                                                  .AndIf(search.RoleName.IsNotNullOrWhiteSpace(), x => x.Name.Contains(search.RoleName));

            var total = await _roleRepository.GetCountAsync(whereExpression);
            if (total == 0)
            {
                return new PageModelVo<RoleDto>(search);
            }

            var entities = _roleRepository
                                .QueryListByClause(whereExpression)
                                .OrderByDescending(x => x.Id)
                                .Skip(search.SkipRows())
                                .Take(search.PageSize)
                                .ToList();
            var dtos = Mapper.Map<List<RoleDto>>(entities);

            return new PageModelVo<RoleDto>(search, dtos, total);
        }
    }
}
